#include "filebrowser.h"
#include <QMessageBox>
#include <QDebug>
#include <QLabel>
#include <QFileIconProvider>
#include <QPainter>
#include <QInputDialog>

FileBrowser::FileBrowser( QWidget *parent )
    : QWidget(parent)
{
    init();

}

FileBrowser::FileBrowser( QString homedir, QWidget *parent )
    :QWidget (parent)
{
    init(homedir);
    setBasePath(homedir);
    //qDebug("Home dir es -> "+homedir.toLatin1());
}

void FileBrowser::init(QString home){
    grabGesture(Qt::TapAndHoldGesture);
    grabGesture(Qt::TapGesture);

    setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
    QVBoxLayout *layout= new QVBoxLayout(this);
    layout->setMargin(0);
    layout->setSpacing(0);
    copyProgress = new QProgressBar(this);
    copyProgress->setVisible(false);
    copyProgress->setFormat("%v");
    listView= new QListView(this);
    tableView= new QTableView(this);
    tableView->setShowGrid(false);
    tableView->verticalHeader()->setVisible(false);
    tableView->setIconSize(QSize(32,32));

    tableView->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents);
    tableView->setSelectionMode(QAbstractItemView::SingleSelection);
    tableView->setColumnWidth(0,400);
    if (DDeviceInformation::isTouchable()){
        tableView->setAlternatingRowColors(true);
        copyProgress->setTextVisible(false);
        connect(tableView, SIGNAL(clicked(QModelIndex)), this, SLOT(openResource()));
        connect(listView, SIGNAL(clicked(QModelIndex)), this, SLOT(openResource()));
    }
    layout->addWidget(copyProgress);
    layout->addWidget(listView);
    layout->addWidget(tableView);
    setLayout(layout);

    QDesktopWidget *desk=QApplication::desktop();
    if (desk->screenGeometry().height()<900 && desk->screenGeometry().width()<900 || DDeviceInformation::isTouchable()){ //Probably a mobile device
        setListViewConfiguration();
    }
    else{
        setIconViewConfiguration();
    }

    listView->setSelectionRectVisible(false);

    dirModel = new QFileSystemModel(this);
    dirModel->setReadOnly(false);
    dirModel->setRootPath(home);
    dirModel->setFilter(QDir::AllEntries);
    dirModel->setNameFilters(QStringList("[^.]*"));
    dirModel->setNameFilterDisables(false);

    listdelegate= new ListViewDelegate();
    listView->setItemDelegate(listdelegate);
    listdelegate->setBasePath(home);
    listView->setModel(dirModel);

    tableView->setItemDelegate(listdelegate);
    tableView->setModel(dirModel);
    tableView->setHidden(true);

    listView->setContextMenuPolicy(Qt::CustomContextMenu);
    tableView->setContextMenuPolicy(Qt::CustomContextMenu);
    connect(listView,SIGNAL(customContextMenuRequested(QPoint)),this,SLOT(menu(QPoint )));
    connect(tableView,SIGNAL(customContextMenuRequested(QPoint)),this,SLOT(menu(QPoint )));
    connect(this,SIGNAL(changeDirectory(QString)),this,SLOT(adaptTreeViewColumns()));


    currentPath = home;
    setRootPath(currentPath, false);
    listView->setCurrentIndex(dirModel->index(currentPath));
    tableView->setCurrentIndex(dirModel->index(currentPath));

    clipboard = QApplication::clipboard();
    mimeData = clipboard->mimeData();
}

QString FileBrowser::getCurrentPath()
{
    return currentPath;
}

void FileBrowser::goBack()
{
    if (history.count()>0)
    {
        future.push(currentPath);
        currentPath = history.pop();
        setRootPath(currentPath, false);
    }
}

void FileBrowser::goForward()
{
    if (future.count()>0)
    {
        history.push(currentPath);
        currentPath = future.pop();
        setRootPath(currentPath, false);
    }
}

void FileBrowser::goUp()
{
    changeDir(getRootIndex().parent());
}

void FileBrowser::goHome()
{
    if (dirModel->isDir(dirModel->index(basePath)))
        setRootPath(basePath);
    else
        setRootPath(QDir::homePath());
    refresh();
}

void FileBrowser::refresh()
{
    dirModel->setRootPath(currentPath);
}

void FileBrowser::setRootPath(const QString& path, bool remember)
{
    changeDir(dirModel->index(path), remember);
}

void FileBrowser::changeDir(const QModelIndex& index, bool remember)
{
    QModelIndex dir = index.sibling(index.row(), 0);
    if (!dirModel->isDir(dir))
        dir = dir.parent();

    if (dir != getRootIndex() && dirModel->isDir(dir))
    {
        if (remember)
        {
            future.clear();
            history.push(currentPath);
        }
        currentPath = dirModel->filePath(dir);
        listView->setRootIndex(dir);
        tableView->setRootIndex(dir);

    }
    updateActions();
    emit changeDirectory(currentPath);
    refresh();
}

void FileBrowser::updateActions()
{
    emit setBackButtonEnabled(!history.isEmpty());
    emit setNextButtonEnabled(!future.isEmpty());
    emit setUpButtonEnabled(!dirModel->fileInfo(getCurrentIndex()).isRoot());

}

QFileSystemModel * FileBrowser::getDirModel(){
    return dirModel;

}

void FileBrowser::setContextMenu(ContextMenu *menu){
    fbMenu=menu;
    connect(fbMenu, SIGNAL(openTriggered()), this, SLOT(openResource()));
    connect(fbMenu, SIGNAL(copyTriggered()), this, SLOT(copyResourceToBuffer()));
    connect(fbMenu, SIGNAL(cutTriggered()), this, SLOT(cutResourceToBuffer()));
    connect(fbMenu, SIGNAL(pasteTriggered()), this, SLOT(pasteResource()));
    connect(fbMenu, SIGNAL(renameTriggered()), this, SLOT(renameResource()));
    connect(fbMenu, SIGNAL(deleteTriggered()), this, SLOT(deleteResourceRequest()));
    connect(fbMenu, SIGNAL(createFolderTriggered()), this, SLOT(createFolder()));
}

int FileBrowser::viewMode()
{
    return currentViewMode;
}

QWidget *FileBrowser::listViewWidget()
{
        return listView;
}

QWidget *FileBrowser::tableViewWidget()
{
        return tableView;
}


void FileBrowser::menu(QPoint pos)
{
    //qDebug() << "Seleccionado al entrar al menu " << dirModel->filePath(QModelIndex(getCurrentIndex()));
    // for most widgets
    //QPoint globalPos = this->mapToGlobal(pos);
    // for QAbstractScrollArea and derived classes you would use:
     QPoint globalPos = listView->viewport()->mapToGlobal(pos);

    if(dirModel->filePath(listView->indexAt(pos)).length()==0){
        listView->clearSelection();
        listView->setCurrentIndex(dirModel->index(currentPath));
        tableView->clearSelection();
        tableView->setCurrentIndex(dirModel->index(currentPath));
        fbMenu->setRenameEnabled(false);
        fbMenu->setDeleteEnabled(false);
        fbMenu->setOpenEnabled(false);
    }
    else{
        fbMenu->setRenameEnabled(true);
        fbMenu->setDeleteEnabled(true);
        fbMenu->setOpenEnabled(true);
    }

    if (dirModel->isDir(getCurrentIndex()))
        fbMenu->setNewFolderEnabled(true);
    else
        fbMenu->setNewFolderEnabled(false);

    if (QApplication::clipboard()->text().length()>0 || QApplication::clipboard()->mimeData()->hasUrls())
        fbMenu->setPasteEnabled(true);

    QAction* selectedItem =  fbMenu->exec(globalPos);

    if (selectedItem)
    {   // something was chosen, do stuff
       //qDebug() << "test" << selectedItem->text();

    }
    else
    {
        // nothing was chosen
    }
}

void FileBrowser::setIconViewConfiguration(){
    listView->setViewMode(QListView::IconMode);
    currentViewMode=FileBrowser::icon;
    listView->setIconSize(QSize(32,32));
    if (DDeviceInformation::isTouchable()){
        listView->setGridSize(QSize(192,96));
        listView->setAlternatingRowColors(false);
    }
    else
        listView->setGridSize(QSize(96,64));

    listView->setResizeMode(QListView::Adjust);
    if (listView->isHidden()){
        tableView->setHidden(true);
        listView->setHidden(false);
    }
}

void FileBrowser::setListViewConfiguration(){
    listView->setViewMode(QListView::ListMode);
    listView->setIconSize(QSize(32,32));
    if (DDeviceInformation::isTouchable()){
        listView->setAlternatingRowColors(true);
        listView->setGridSize(QSize(64,48));
    }
    else{
        listView->setGridSize(QSize(34,34));
    }
    currentViewMode=FileBrowser::list;
    listView->setResizeMode(QListView::Adjust);
    if (listView->isHidden()){
        tableView->setHidden(true);
        listView->setHidden(false);
    }
}

void FileBrowser::setDetailViewConfiguration(){
    currentViewMode=FileBrowser::detail;
    if (tableView->isHidden()){
        tableView->setHidden(false);
        listView->setHidden(true);
    }
}

void FileBrowser::adaptTreeViewColumns ()
{
    if (tableView->isVisible())
        tableView->setColumnWidth(0,this->width()/2);
    else
        tableView->setColumnWidth(0,400);
    tableView->horizontalHeader()->setStretchLastSection(true);
}


void FileBrowser::openResource(){    
    QModelIndex index;
    index=getCurrentIndex();
    if (dirModel->isDir(index))
        changeDir(index);
    else
        QDesktopServices::openUrl("file:///"+dirModel->filePath(index));
}

void FileBrowser::deleteResourceRequest(){
    QMessageBox msg;
    QModelIndex index= getCurrentIndex();
    //qDebug()<< "los estilos son" << DDeviceInformation::getStyleName();

    QFile qss(DDeviceInformation::getStyleName().replace(".qss","_qmessagebox.qss"));
    if( ! qss.open( QIODevice::ReadOnly ) )
        qDebug() << "Unable to open qss file " << qss.fileName();
    else if( qss.isOpen() )
    {
        QString styleSheet = QLatin1String(qss.readAll());
        msg.setStyleSheet(styleSheet );

    }
    //msg.setStyleSheet("QWidget {color: white;}");
    msg.setWindowTitle(tr("Delete?"));
    msg.setText("Delete " +dirModel->filePath(index)+ " ?");
    if (DDeviceInformation::isTouchable())
        msg.setWindowState(Qt::WindowMaximized);

    msg.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
    int confirm = msg.exec();

    if (confirm==QMessageBox::Yes)
        deleteResource(index);
}

void FileBrowser::deleteCutResource(){
    deleteResource(copied_resource);
}

void FileBrowser::deleteResource(QModelIndex index){
    if ( dirModel->isDir(index)){
        rmFolder(dirModel->filePath(index));
    }
    else if (!dirModel->isDir(index))
        dirModel->remove(index);
}

void FileBrowser::renameResource(){

    if (listView->isVisible())
        listView->edit(getCurrentIndex());
    else if (tableView->isVisible())
        tableView->edit(getCurrentIndex());
    refresh();
}

void FileBrowser::copyResourceToBuffer(){    
    copied_resource=getCurrentIndex();
    QMimeData *data= new QMimeData();
    QList <QUrl> lUrl;
    lUrl.append(QUrl::fromLocalFile(dirModel->filePath(QModelIndex(copied_resource))));
    data->setUrls(lUrl);
    data->setText(QUrl::fromLocalFile(dirModel->filePath(QModelIndex(copied_resource))).toString());
    QApplication::clipboard()->setMimeData(data);
    //qDebug() <<"Copiado " << data->text();
}

void FileBrowser::cutResourceToBuffer(){
    copyResourceToBuffer();
    cutResource=true;
}

void FileBrowser::pasteResource(){
    copyFromClipboard();
    QApplication::clipboard()->clear();

    //QApplication::clipboard()->mimeData()->clear();
}

bool FileBrowser::copyFromClipboard(){
    bool returnValue=false;
    mimeData = clipboard->mimeData();
    if (mimeData->hasUrls()){
        //qDebug() << "Pegando " << mimeData->text();
        //TODO: split "\n" and iterate for paste  all files
        QList <QUrl> lUrl=mimeData->urls();
        QFile file;
        for (int i=0;i<lUrl.count();i++){
            file.setFileName(lUrl.at(i).toLocalFile());
            if (file.exists()){
                if (dirModel->isDir(dirModel->index(file.fileName()))){
                    if (cutResource){
                        if (!file.rename(file.fileName(),QDir::toNativeSeparators(currentPath)+QDir::separator()+ QDir::toNativeSeparators(file.fileName()).split(QDir::separator()).last()))
                            qDebug() << "Error copying " << QDir::toNativeSeparators(file.fileName()) << "to " << currentPath+QDir::separator()+ QDir::toNativeSeparators(file.fileName()).split(QDir::separator()).last() << file.errorString();
                        else
                            returnValue=true;
                        cutResource=false;
                    }
                    else {
                        copyProgress->setMaximum(0);
                        copyProgress->setVisible(true);
                        if (copyFolder(file.fileName(),this->currentPath+QDir::separator()+QDir::toNativeSeparators(file.fileName()).split(QDir::separator()).last()))
                            returnValue=true;
                        copyProgress->setVisible(false);
                    }
                }
                else{
                    //qDebug() << file.fileName() << "mime ";//QDir::toNativeSeparators(currentPath+QDir::separator()+
                    if (cutResource){
                        if (!file.rename(file.fileName(),QDir::toNativeSeparators(currentPath)+QDir::separator()+ QDir::toNativeSeparators(file.fileName()).split(QDir::separator()).last()))
                            qDebug() << "Error copying " << QDir::toNativeSeparators(file.fileName()) << "to " << currentPath+QDir::separator()+ QDir::toNativeSeparators(file.fileName()).split(QDir::separator()).last() << file.errorString();
                        else
                            returnValue=true;
                        cutResource=false;
                    }
                    else if ( !file.copy(QDir::toNativeSeparators(currentPath)+QDir::separator()+ QDir::toNativeSeparators(file.fileName()).split(QDir::separator()).last() )){
                        qDebug() << "Error copying " << QDir::toNativeSeparators(file.fileName()) << "to " << currentPath+QDir::separator()+ QDir::toNativeSeparators(file.fileName()).split(QDir::separator()).last() << file.errorString();
                    }
                    else
                        returnValue=true;
                }
            }
        }
    }
    return returnValue;
}

QModelIndex FileBrowser::getCurrentIndex(){
    QModelIndex index;
    if (listView->isVisible())
        index=listView->currentIndex();
    else if (tableView->isVisible())
        index=tableView->currentIndex();
    return index;
}

QModelIndex FileBrowser::getRootIndex(){
    QModelIndex index;
    if (listView->isVisible())
        index=listView->rootIndex();
    else if (tableView->isVisible())
        index=tableView->rootIndex();
    return index;
}

void FileBrowser::changeView(int view){
    if (view==FileBrowser::icon)
        setIconViewConfiguration();
    else if(view==FileBrowser::list)
        setListViewConfiguration();
    else if(view==FileBrowser::detail)
        setDetailViewConfiguration();
}

bool FileBrowser::copyFolder(QString sourceFolder, QString destFolder)
{
    bool returnValue=false;

    QDir sourceDir(sourceFolder);
    if(!sourceDir.exists())
        return false;
    QDir destDir(destFolder);
    if(!destDir.exists())
    {
        destDir.mkdir(destFolder);
    }
    QStringList files = sourceDir.entryList(QDir::Files);
    copyProgress->setMaximum(copyProgress->maximum()+files.count());
    for(int i = 0; i< files.count(); i++)
    {
        copyProgress->setValue(copyProgress->value()+1);
        QString srcName = sourceFolder + QDir::separator() + files[i];
        QString destName = destFolder + QDir::separator() + files[i];
        QFile::copy(srcName, destName);
    }
    files.clear();
    files = sourceDir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot);

    copyProgress->setMaximum(copyProgress->maximum()+files.count());
    for(int i = 0; i< files.count(); i++)
    {
        copyProgress->setValue(copyProgress->value()+1);
        QString srcName = sourceFolder + QDir::separator() + files[i];
        QString destName = destFolder + QDir::separator() + files[i];
        if (destName.compare(srcName + QDir::separator() + files[i])!=0){
            copyFolder(srcName, destName);
            returnValue=true;
        }
    }
    return returnValue;
}

bool FileBrowser::rmFolder(const QString sourceFolder)
{
    QDir dir(sourceFolder);
    if (!dir.exists())
        return true;
    foreach(const QFileInfo &info, dir.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot)) {
        if (info.isDir()) {
            if (!rmFolder(info.filePath()))
                return false;
        } else {
            if (!dir.remove(info.fileName()))
                return false;
        }
    }
    QDir parentDir(QFileInfo(sourceFolder).path());
    return parentDir.rmdir(QFileInfo(sourceFolder).fileName());

}

bool FileBrowser::createFolder(){

    bool ok;
    QString text = QInputDialog::getText(this, tr("New folder"),
                                         tr("Folder name:"), QLineEdit::Normal,
                                         QDir::home().dirName(), &ok);
    if (ok && !text.isEmpty()){
        QDir *dir=new QDir();
        if (dirModel->isDir(getCurrentIndex()))
            dir->setPath(dirModel->filePath(getCurrentIndex()));
        else
            dir->setPath(currentPath);
        return dir->mkdir(text);
    }
    else return false;
}

//Alternative path to user's home directory. Used for home button
void FileBrowser::setBasePath(QString path){
    if (dirModel->isDir(dirModel->index(path)))
        basePath=path;
}


void FileBrowser::setItemWidget(QString path, QWidget *widget){
    listView->setIndexWidget(dirModel->index(path),widget);
}

void FileBrowser::setOverlayStatus(QString path, int status){
    listdelegate->setOverlayStatus(dirModel->index(path).internalId(),status);
}

void FileBrowser::removeOverlayStatus(QString path){
    listdelegate->removeOverlayStatus(dirModel->index(path).internalId());
}

void FileBrowser::setMap(QMap<qint64, int> *map){
    listdelegate->setMap(map);
}

bool FileBrowser::event(QEvent *event)
{
    if (event->type() == QEvent::Gesture){
        return gestureEvent(static_cast<QGestureEvent*>(event));
    }
    return QWidget::event(event);
}

bool FileBrowser::gestureEvent(QGestureEvent *event)
{
    if (QGesture *swipe = event->gesture(Qt::TapAndHoldGesture)){
        //ungrabGesture(Qt::TapGesture);
        tapAndHoldTriggered(static_cast<QTapAndHoldGesture *>(swipe));
    }
    if (QGesture *swipe = event->gesture(Qt::TapGesture)){
        tapTriggered(static_cast<QTapGesture *>(swipe));
    }
    return true;
}

void FileBrowser::tapAndHoldTriggered(QTapAndHoldGesture* gesture)
{
    if (gesture->state() == Qt::GestureStarted) {
        //qDebug("comienaz el tab and hold");
    }
    else if (gesture->state() == Qt::GestureFinished) {
        //grabGesture(Qt::TapGesture);
        QPoint position(gesture->position().toPoint());
        //We need to change from global coordinates to filebrowser ones
        if (listView->isVisible()){
            menu(listView->mapFromGlobal(position));
        }
        else if (tableView->isVisible())
            menu(tableView->mapFromGlobal(position));
    }
}

void FileBrowser::tapTriggered(QTapGesture* gesture)
{
    if (gesture->state() == Qt::GestureStarted) {
        //qDebug() << "comienza el tab";
        setAcceptDrops(false);
        listView->setAcceptDrops(false);
    }
    else if (gesture->state() == Qt::GestureFinished) {
        openResource();
    }
}


